package com.dwy2002.order.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dwy2002.common.Result;
import com.dwy2002.common.utils.JwtUtil;
import com.dwy2002.common.utils.Utils;
import com.dwy2002.common.utils.Validator;
import com.dwy2002.enums.OrderTypeEnum;
import com.dwy2002.enums.Status;
import com.dwy2002.order.mapper.OrdersMapper;
import com.dwy2002.order.service.IOrderStatusLogsService;
import com.dwy2002.order.service.IOrdersService;
import com.dwy2002.order.service.IPaymentRecordsService;
import com.dwy2002.order.service.handler.OrderTypeHandler;
import com.dwy2002.pojo.dto.order.OrderDTO;
import com.dwy2002.pojo.dto.order.OrderStatusLogsDTO;
import com.dwy2002.pojo.dto.order.OrderUpdateDTO;
import com.dwy2002.pojo.dto.order.OrdersPageDTO;
import com.dwy2002.pojo.po.order.OrderStatusLogs;
import com.dwy2002.pojo.po.order.Orders;
import com.dwy2002.pojo.po.users.Users;
import com.dwy2002.pojo.vo.order.OrderVO;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.OrderNumberGenerator.generateOrderNumber;
import static com.dwy2002.common.utils.Utils.*;
import static com.dwy2002.enums.OrderTypeEnum.isValidOrderTypeEnum;
import static com.dwy2002.enums.PaymentMethodEnum.isValidPaymentMethod;
import static com.dwy2002.pojo.po.order.Orders.OrderStatusEnum.*;
import static com.dwy2002.pojo.po.order.Orders.PaymentStatusEnum.isValidPaymentStatus;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/03/06
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    private final JwtUtil jwtUtil;
    private final IPaymentRecordsService paymentRecordsService;
    private final IOrderStatusLogsService orderStatusLogsService;
    @Resource
    private Map<String, OrderTypeHandler> orderTypeHandlers;

    /**
     * 生成订单
     *
     * @param dto 前端传的订单信息
     * @author 杜伟毅
     * @since 2025/3/7 0007 23:09
     */
    @Override
    public Result<Void> generateOrder(OrderDTO dto) {
        Validator.of(dto)
                .notNull(OrderDTO::getOrderType, "订单类型不能为空")
                .mustSatisfy(!isValidOrderTypeEnum(dto.getOrderType()), "没有这个订单类型")
                .notZeroDecimal(OrderDTO::getTotalAmount, "金额不能为0")
                .notNull(OrderDTO::getOrderStatus, "订单状态不能为空")
                .mustSatisfy(!isValidOrderStatus(dto.getOrderStatus()), "没有这个订单状态")
                .notNull(OrderDTO::getPaymentStatus, "支付状态不能为空")
                .mustSatisfy(!isValidPaymentStatus(dto.getOrderStatus()), "没有这个支付状态")
                .notEmpty(OrderDTO::getPaymentMethod, "支付方式不能为空")
                .mustSatisfy(!isValidPaymentMethod(dto.getPaymentMethod()), "没有这个支付方式")
                .validate();
        Users user = jwtUtil.parseToken(Utils.getToken(), Users.class);

        String orderId = IdWorker.get32UUID();
        Orders order = BeanUtil.copyProperties(dto, Orders.class);
        order.setId(orderId);
        order.setOrderNumber(generateOrderNumber());
        order.setUserId(user.getId());
        order.setUserPhone(user.getPhone());
        //暂时先用订单方法生成第三方交易号
        order.setTransactionId(generateOrderNumber());
        boolean save = save(order);

        //根据订单类型选择
        OrderTypeHandler handler = getHandler(dto.getOrderType());
        handler.handle(orderId, dto);

        //保存支付信息
        paymentRecordsService.savePaymentRecord(order);
        return handleResult(save, "订单创建成功", "订单创建失败");
    }

    /**
     * 删除订单
     *
     * @param ids 订单id集合
     * @author 杜伟毅
     * @since 2025/3/8 0008 22:27
     */
    @Override
    public Result<Void> deleteOrder(List<String> ids) {
        // 1. 校验整体非空
        if (isListEmpty(ids)) return fail(Status.BAD_REQUEST, "id不能为空");

        // 2. 过滤有效ID
        List<String> validIds = ids.stream()
                .filter(id -> !isEmptyOrNull(id))
                .collect(Collectors.toList());

        //3.批量查询有效订单并立即校验
        List<Orders> existingOrders = getBatchByIds(validIds);
        if (CollectionUtils.isEmpty(existingOrders)) {
            return fail(Status.BAD_REQUEST, "未找到有效订单");
        }

        // 4. 按订单类型删除关联数据
        existingOrders.forEach(orders -> {
            OrderTypeHandler handler = getHandler(orders.getOrderType());
            handler.deleteHandle(orders.getId());
        });

        // 4. 批量删除订单
        boolean success = removeByIds(validIds);
        return handleResult(success, "订单删除成功", "订单删除失败");
    }

    /**
     * 订单分页查询
     *
     * @param dto 订单分页数据DTO
     * @author 杜伟毅
     * @since 2025/3/9 0009 14:47
     */
    @Override
    public Result<Page<Orders>> getOrdersPage(OrdersPageDTO dto) {
        Validator.of(dto)
                .mustSatisfy(isPageNull(dto.getPageNo(), dto.getPageSize()), "请传入分页数据")
                .mustSatisfy(isPageZero(dto.getPageNo(), dto.getPageSize()), "分页数据不能为0")
                .validate();

        LambdaQueryWrapper<Orders> lqw = new LambdaQueryWrapper<>();
        lqw.like(!isEmptyOrNull(dto.getUserPhone()), Orders::getOrderNumber, dto.getUserPhone())
                .like(!isEmptyOrNull(dto.getPaymentMethod()), Orders::getPaymentMethod, dto.getPaymentMethod())
                .eq(!isEmptyOrNull(dto.getOrderNumber()), Orders::getOrderNumber, dto.getOrderNumber())
                .orderBy(dto.getCreatedEnabled(), dto.getCreatedIsAsc(), Orders::getCreatedAt)
                .orderBy(dto.getUpdatedEnabled(), dto.getUpdatedIsAsc(), Orders::getUpdatedAt)
                .orderBy(dto.getTotalAmountEnabled(), dto.getTotalAmountIsAsc(), Orders::getTotalAmount)
                .eq(dto.getOrderTypeEnabled(), Orders::getOrderType, dto.getOrderType())
                .eq(dto.getOrderStatusEnabled(), Orders::getOrderStatus, dto.getOrderStatus())
                .eq(dto.getPaymentStatusEnabled(), Orders::getPaymentStatus, dto.getPaymentStatus());

        Page<Orders> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        Page<Orders> ordersPage = this.page(page, lqw);

        return success(ordersPage);
    }

    /**
     * 有限制的修改订单
     *
     * @param dto 修改订单DTO
     * @author 杜伟毅
     * @since 2025/3/8 0008 23:01
     */
    @Override
    public Result<Void> updateOrder(OrderUpdateDTO dto) {
        if (isEmptyOrNull(dto.getId())) return fail(Status.BAD_REQUEST, "id不能为空");
        LambdaUpdateWrapper<Orders> luw = new LambdaUpdateWrapper<>();
        luw.eq(Orders::getId, dto.getId())
                .set(Orders::getRemark, dto.getRemark());
        boolean update = update(luw);
        return handleResult(update, "修改成功", "修改失败");
    }

    /**
     * 获取订单详情
     *
     * @param id 订单id
     * @author 杜伟毅
     * @since 2025/3/11 0011 18:12
     */
    @Override
    public Result<OrderVO> getOrderDetails(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "id不允许为空");
        Orders orders = getById(id);
        if (ObjectUtils.isEmpty(orders)) return fail(Status.BAD_REQUEST, "id无效");

        OrderVO orderVO = BeanUtil.copyProperties(orders, OrderVO.class);

        //根据订单类型选择
        OrderTypeHandler handler = getHandler(orderVO.getOrderType());
        handler.getDetailsHandle(orderVO);

        return success(orderVO);
    }

    /**
     * 完成订单
     *
     * @param id 订单id
     * @author 杜伟毅
     * @since 2025/3/15 0015 23:17
     */
    @Override
    public Result<Void> accomplishOrder(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "id不能为空");
        Orders order = getById(id);
        if (ObjectUtils.isEmpty(order)) return fail(Status.BAD_REQUEST, "id无效");
        if (!Orders.OrderStatusEnum.isClosable(order.getOrderStatus()) && !Orders.PaymentStatusEnum.isClosable(order.getPaymentStatus())) {
            return fail(Status.BAD_REQUEST, "当前状态不可完成订单");
        }
        LambdaUpdateWrapper<Orders> luw = new LambdaUpdateWrapper<>();
        luw.eq(Orders::getId, id)
                .set(Orders::getOrderStatus, COMPLETED.getCode());
        boolean update = update(luw);

        // 记录状态变更日志
        recordStatusLog(order, COMPLETED.getCode());

        return handleResult(update, "关闭成功", "关闭失败");
    }

    /**
     * 完成订单(定时任务)
     *
     * @author 杜伟毅
     * @since 2025/3/15 0015 23:18
     */
    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    @Override
    public void batchAccomplishOrder() {
        LambdaQueryWrapper<Orders> lqw = new LambdaQueryWrapper<>();
        lqw.select(Orders::getId)
                .eq(Orders::getOrderStatus, PAID.getCode())
                .eq(Orders::getPaymentStatus, PAID.getCode());
        List<String> ids = list(lqw)
                .stream()
                .map(Orders::getId)
                .toList();

        if (!isListEmpty(ids)) {
            LambdaUpdateWrapper<Orders> luw = new LambdaUpdateWrapper<>();
            luw.in(Orders::getId, ids)
                    .set(Orders::getOrderStatus, COMPLETED.getCode());
            //批量更新订单
            update(luw);
        }
    }

    //辅助方法----------------------------------------------------------------


    /**
     * 根据订单类型获取处理器
     *
     * @param orderType 订单类型
     * @author 杜伟毅
     * @since 2025/3/11 0011 22:58
     */
    private OrderTypeHandler getHandler(Integer orderType) {
        String handlerName = OrderTypeEnum.getHandlerNameByCode(orderType);
        return Optional.ofNullable(orderTypeHandlers.get(handlerName))
                .orElseThrow(() -> new IllegalArgumentException("找不到订单处理器"));
    }

    /**
     * 批量查询订单
     *
     * @param ids 订单id集合
     * @return 查询到的订单
     * @author 杜伟毅
     * @since 2025/3/13 0013 10:35
     */
    private List<Orders> getBatchByIds(List<String> ids) {
        LambdaQueryWrapper<Orders> lqw = new LambdaQueryWrapper<>();
        lqw.in(Orders::getId, ids);
        List<Orders> orders = list(lqw);
        return isListEmpty(orders) ? Collections.emptyList() : orders;
    }

    /**
     * 记录订单状态变更日志
     *
     * @author 杜伟毅
     * @since 2025/3/15 0015 15:27
     */
    private void recordStatusLog(Orders order, Integer newStatus) {
        OrderStatusLogsDTO logsDTO = new OrderStatusLogsDTO()
                .setOrderId(order.getId())
                .setOldStatus(order.getOrderStatus())
                .setNewStatus(newStatus)
                .setOperatorType(OrderStatusLogs.OperatorTypeEnum.USER.getCode())
                .setRemark("用户自定义完成");
        orderStatusLogsService.recordOrderStatusLog(logsDTO);
    }
}
